package br.affCorp.controller.rdf.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import br.affCorp.controller.rdf.GenericRDF;
import br.affCorp.model.ImagemPerfilDTO;
import br.affCorp.model.ObjetoDeAprendizagemDTO;
import br.affCorp.model.UsuarioDTO;
import br.affCorp.util.vocabulary.rdf.LOM;
import br.affCorp.util.vocabulary.rdf.SIOC;
import br.util.AFFCorpWebUtil;
import br.util.AppJsfUtil;
import br.util.AppEnums.Arquivo;

import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.sparql.core.ResultBinding;
import com.hp.hpl.jena.sparql.vocabulary.FOAF;

public class UsuarioRDF extends GenericRDF {

	private ObjetoDeAprendizagemRDF objetoDeAprendizagemRDF;

	public void atualizar(UsuarioDTO usuarioDTO) {

		Model modelNovo = ModelFactory.createDefaultModel();
		Model modelAntigo = ModelFactory.createDefaultModel();

		Resource usuarioResource = preencherResource(usuarioDTO, modelNovo);

		for (UsuarioDTO amigo : usuarioDTO.getAmigos()) {
			Resource amigoResource = preencherResource(amigo, modelNovo);
			associarContato(usuarioResource, amigoResource, modelNovo);
		}

		modelAntigo.read(this.obterArquivoRDF(usuarioDTO.getDominio(),
				usuarioDTO.getDominio()), "");

		setModel(modelAntigo.difference(modelNovo).union(modelAntigo));

		Map<String, String> map = new HashMap<String, String>();
		map.put("foaf", FOAF.getURI());
		map.put("sioc", SIOC.getURI());
		map.put("lom", LOM.getURI());
		getModel().setNsPrefixes(map);

		super.salvarArquivoRDF(getModel(), usuarioDTO.getDominio(), usuarioDTO
				.getDominio());

	}

	public Resource preencherResource(UsuarioDTO usuarioDTO, Model model) {
		String resourceId = super.obterResourceID(usuarioDTO, usuarioDTO
				.getUid());

		Map<String, String> map = new HashMap<String, String>();
		map.put("foaf", FOAF.getURI());
		model.setNsPrefixes(map);

		Resource resource = model.createResource(resourceId, FOAF.Person);

		if (!AppJsfUtil.isNullOrEmpty(usuarioDTO.getLogin())) {
			resource.addProperty(FOAF.accountName, usuarioDTO.getLogin());
		}

		if (!AppJsfUtil.isNullOrEmpty(usuarioDTO.getNickName())) {
			resource.addProperty(FOAF.nick, usuarioDTO.getNickName());
		}
		if (!AppJsfUtil.isNullOrEmpty(usuarioDTO.getNome())) {
			resource.addProperty(FOAF.firstName, usuarioDTO.getNome());
		}
		if (!AppJsfUtil.isNullOrEmpty(usuarioDTO.getSobreNome())) {
			resource.addProperty(FOAF.surname, usuarioDTO.getSobreNome());
		}
		if (!AppJsfUtil.isNullOrEmpty(usuarioDTO.getEmail())) {
			resource.addProperty(FOAF.mbox, usuarioDTO.getEmail());
		}
		if (!AppJsfUtil.isNullOrEmpty(usuarioDTO.getImagemPerfil().getUrl())) {
			resource.addProperty(FOAF.img, usuarioDTO.getImagemPerfil()
					.getUrl());
		}

		return resource;
	}

	public Resource associarUsuarioObjetoDeAprendizagem(
			ObjetoDeAprendizagemDTO objetoDeAprendizagemDTO) {

		Model usuarioModel = ModelFactory.createDefaultModel();

		UsuarioDTO usuarioDTO = objetoDeAprendizagemDTO.getDono();

		String resourceId = super.obterResourceID(usuarioDTO, usuarioDTO
				.getUid());

		Resource resourceSIOC = usuarioModel.createResource(resourceId,
				SIOC.User);

		this.associarObjetoDeAprendizagemUsuario(objetoDeAprendizagemDTO);

		return resourceSIOC;
	}

	private void associarObjetoDeAprendizagemUsuario(
			ObjetoDeAprendizagemDTO objetoDeAprendizagemDTO) {

		Model usuarioModel = ModelFactory.createDefaultModel();

		usuarioModel.read(this.obterArquivoRDF(objetoDeAprendizagemDTO
				.getDono().getDominio(), objetoDeAprendizagemDTO.getDono()
				.getDominio()), "");

		String resourceId = super.obterResourceID(objetoDeAprendizagemDTO
				.getDono(), objetoDeAprendizagemDTO.getDono().getUid());

		Resource foafPerson = usuarioModel.getResource(resourceId);

		Model documentModel = ModelFactory.createDefaultModel();

		Resource foafDocument = documentModel.createResource(super
				.obterResourceID(objetoDeAprendizagemDTO.getDono())
				+ "/"
				+ objetoDeAprendizagemDTO.getDono().getDominio().concat(
						Arquivo.RDF.getExtensao()), FOAF.Document);

		objetoDeAprendizagemRDF = new ObjetoDeAprendizagemRDF();

		foafDocument.addProperty(SIOC.has_owner, objetoDeAprendizagemRDF
				.associarObjetoDeAprendizagemUsuario(objetoDeAprendizagemDTO,
						documentModel));

		Map<String, String> map = new HashMap<String, String>();

		map.put("foaf", FOAF.getURI());
		map.put("sioc", SIOC.getURI());
		map.put("lom", LOM.getURI());

		usuarioModel.setNsPrefixes(map);

		usuarioModel.add(documentModel);
		foafPerson.addProperty(FOAF.publications, foafDocument);

		super.salvarArquivoRDF(usuarioModel, objetoDeAprendizagemDTO.getDono()
				.getDominio(), objetoDeAprendizagemDTO.getDono().getDominio());
	}

	public UsuarioDTO obterPorUID(UsuarioDTO usuarioDTO) {
		getModel().read(
				this.obterArquivoRDF(usuarioDTO.getDominio(), usuarioDTO
						.getDominio()), "");

		StringBuffer querySB = new StringBuffer();

		String uid = super.obterValorResourceID(usuarioDTO.getDominio(),
				usuarioDTO.getUid());
		usuarioDTO.setUid(uid);
		String enderecoCompletoUsuario = super.obterResourceID(usuarioDTO,
				usuarioDTO.getUid());

		String id = "<" + enderecoCompletoUsuario + ">";

		querySB.append(" PREFIX foaf: <" + FOAF.getURI() + "> 		");
		querySB.append(" SELECT 									");
		querySB.append(" 	?id	 								");
		querySB.append(" 	?nick	 								");
		querySB.append(" 	?img	 								");
		querySB.append(" 	?firstName	 							");
		querySB.append(" 	?surname	 							");
		querySB.append(" WHERE	 									");
		querySB.append(" 	{	 									");
		querySB.append("  		?id	 foaf:nick ?nick .	  		");
		querySB.append("  		OPTIONAL {       						  		");
		querySB.append("  		?id foaf:firstName ?firstName . 						");
		querySB.append("  		?id foaf:surname ?surname . 						");
		querySB.append("  		?id foaf:img ?img . 						");
		querySB.append("  		}									  		");
		querySB.append("  		FILTER (?id = " + id + ")								");
		querySB.append(" 	}										");

		Query query = QueryFactory.create(querySB.toString());

		QueryExecution qe = QueryExecutionFactory.create(query, getModel());
		try {
			ResultSet results = qe.execSelect();
			if (results.hasNext()) {
				ResultBinding res = (ResultBinding) results.next();
				RDFNode rdfNode = res.get("id");

				Resource resource = getModel().getResource(rdfNode.toString());

				return this.obterUsuario(resource, usuarioDTO);
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			qe.close();
		}

		return null;
	}

	public Collection<ObjetoDeAprendizagemDTO> obterObjetosDeAprendizagemDoUsuario(
			UsuarioDTO usuarioDTO) {
		Collection<ObjetoDeAprendizagemDTO> oas = new ArrayList<ObjetoDeAprendizagemDTO>();
		getModel().read(
				this.obterArquivoRDF(usuarioDTO.getDominio(), usuarioDTO
						.getDominio()), "");

		StringBuffer querySB = new StringBuffer();

		String uid = super.obterValorResourceID(usuarioDTO.getDominio(),
				usuarioDTO.getUid());
		usuarioDTO.setUid(uid);
		String enderecoCompletoUsuario = super.obterResourceID(usuarioDTO,
				usuarioDTO.getUid());

		String id = "<" + enderecoCompletoUsuario + ">";

		querySB.append(" PREFIX foaf: <" + FOAF.getURI() + "> 		");
		querySB.append(" PREFIX sioc: <" + SIOC.getURI() + "> 		");
		querySB.append(" PREFIX lom: <" + LOM.getURI() + "> 		");
		querySB.append(" SELECT 									");
		querySB.append(" 	?titulo	 								");
		querySB.append(" 	?descricao	 							");
		querySB.append(" 	?oas	 							");
		querySB.append(" WHERE	 									");
		querySB.append(" 	{	 									");
		querySB.append("  		?id foaf:publications ?arquivo		.	  		");
		querySB.append("  		?arquivo sioc:has_owner ?oas		.	  		");
		querySB.append("  		?oas lom:description ?descricao		.	  		");
		querySB.append("  		?oas lom:title ?titulo		.	  		");
		querySB.append("  		FILTER (?id = " + id + ")								");
		querySB.append(" 	}										");

		Query query = QueryFactory.create(querySB.toString());

		QueryExecution qe = QueryExecutionFactory.create(query, getModel());

		objetoDeAprendizagemRDF = new ObjetoDeAprendizagemRDF();

		try {
			ResultSet results = qe.execSelect();
			if (results.hasNext()) {
				while (results.hasNext()) {
					ResultBinding res = (ResultBinding) results.next();
					RDFNode rdfNode = res.get("oas");

					Resource resource = getModel().getResource(
							rdfNode.toString());

					ObjetoDeAprendizagemDTO objetoDeAprendizagem = objetoDeAprendizagemRDF
							.obterObjetoDeAprendizagem(resource);
					objetoDeAprendizagem.setLocalizacao(res.get("oas").toString());
					oas.add(objetoDeAprendizagem);
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			qe.close();
		}
		return oas;
	}

	public Collection<UsuarioDTO> obterContatosDoOrkut(UsuarioDTO usuarioDTO) {
		return this.obterContatosDoOrkutPorFiltro(usuarioDTO, "");
	}

	public Collection<UsuarioDTO> obterContatosDoOrkutPorFiltro(
			UsuarioDTO usuarioDTO, String contato) {

		// getModel().read(this.obterArquivoRDF(usuarioDTO.getDominio(),
		// usuarioDTO.getDominio()), "");

		Model model = ModelFactory.createDefaultModel();
		model.read(this.obterArquivoRDF(usuarioDTO.getDominio(), usuarioDTO
				.getDominio()), "");

		Collection<UsuarioDTO> amigos = new ArrayList<UsuarioDTO>();

		StringBuffer querySB = new StringBuffer();

		querySB.append(" PREFIX foaf: <" + FOAF.getURI() + "> 		");
		querySB.append(" SELECT 									");
		querySB.append(" 	?friend	 								");
		querySB.append(" 	?nick	 								");
		querySB.append(" 	?img	 								");
		querySB.append(" 	?firstName	 							");
		querySB.append(" 	?surname	 							");
		querySB.append(" WHERE { 									");
		querySB.append(" 	{	 									");
		querySB.append("  		?person	foaf:knows ?friend		.	  		");
		querySB.append("  		?friend	foaf:nick ?nick		.	  		");
		querySB.append("  		?friend	foaf:img ?img		.	  		");
		querySB.append("  		?friend	foaf:firstName ?firstName		.	  		");
		querySB.append("  		?friend	foaf:surname ?surname		.	  		");

		querySB.append("  		FILTER (REGEX(?nick, \"" + contato
				+ "\", \"i\")			  		");
		querySB.append("  	|| REGEX(?firstName, \"" + contato
				+ "\", \"i\")			  		");
		querySB.append("  	|| REGEX(?surname, \"" + contato
				+ "\", \"i\"))			  		");
		querySB.append(" 	}											");
		querySB.append(" }											");

		querySB.append(" ORDER BY ?nick							");

		Query query = QueryFactory.create(querySB.toString());

		QueryExecution qe = QueryExecutionFactory.create(query, model);
		try {
			ResultSet results = qe.execSelect();
			if (results.hasNext()) {
				while (results.hasNext()) {
					ResultBinding res = (ResultBinding) results.next();
					RDFNode rdfNode = res.get("friend");

					Resource resource = model.getResource(rdfNode.toString());

					UsuarioDTO amigo = this.obterUsuario(resource);
					amigo.setUid(res.get("friend").toString());
					amigos.add(amigo);
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			qe.close();
		}
		return amigos;
	}

	private UsuarioDTO obterUsuario(Resource resource) {

		UsuarioDTO usuarioDTO = this.obterUsuario(resource, new UsuarioDTO());

		return usuarioDTO;
	}

	private UsuarioDTO obterUsuario(Resource resource, UsuarioDTO usuarioDTO) {

		String login = obterValorDaPropriedade(resource, FOAF.accountName);
		String nick = obterValorDaPropriedade(resource, FOAF.nick);
		String nome = obterValorDaPropriedade(resource, FOAF.firstName);
		String sobreNome = obterValorDaPropriedade(resource, FOAF.surname);
		String email = obterValorDaPropriedade(resource, FOAF.mbox);
		String caminhoImagemPerfil = obterValorDaPropriedade(resource, FOAF.img);

		if (!AFFCorpWebUtil.isNullOrEmpty(login)) {
			if (AFFCorpWebUtil.isNullOrEmpty(usuarioDTO.getLogin())) {
				usuarioDTO.setLogin(login);
			}
		}
		if (!AFFCorpWebUtil.isNullOrEmpty(nick)) {
			if (AFFCorpWebUtil.isNullOrEmpty(usuarioDTO.getNickName())) {
				usuarioDTO.setNickName(nick);
			}
		}
		if (!AFFCorpWebUtil.isNullOrEmpty(nome)) {
			if (AFFCorpWebUtil.isNullOrEmpty(usuarioDTO.getNome())) {
				usuarioDTO.setNome(nome);
			}
		}
		if (!AFFCorpWebUtil.isNullOrEmpty(sobreNome)) {
			if (AFFCorpWebUtil.isNullOrEmpty(usuarioDTO.getSobreNome())) {
				usuarioDTO.setSobreNome(sobreNome);
			}
		}
		if (!AFFCorpWebUtil.isNullOrEmpty(email)) {
			if (AFFCorpWebUtil.isNullOrEmpty(usuarioDTO.getEmail())) {
				usuarioDTO.setEmail(email);
			}
		}
		if (!AFFCorpWebUtil.isNullOrEmpty(caminhoImagemPerfil)) {
			usuarioDTO.setImagemPerfil(new ImagemPerfilDTO());
			usuarioDTO.getImagemPerfil().setUrl(caminhoImagemPerfil);
		}

		return usuarioDTO;
	}

	private void associarContato(Resource usuario, Resource amigo, Model model) {
		if ((!AppJsfUtil.isNullOrEmpty(usuario))
				&& (!AppJsfUtil.isNullOrEmpty(amigo))) {
			usuario.addProperty(FOAF.knows, amigo);
		}
	}

}
